www.gusucode.com > VC++ 编写软件自动升级服务源代码 > VC++ 编写软件自动升级服务源代码/gusucode/updater_src0.8.1.6/NetworkFileObject.cpp
/******************************************************************** created: 2005/10/31 created: 31:10:2005 9:46 filename: Network.cpp file path: Updater file base: NetworkFileObject file ext: cpp author: Geert van Horrik purpose: *********************************************************************/ //********************************************************************* // INCLUDES //********************************************************************* #include "stdafx.h" #include "Updater.h" #include "NetworkFileObject.h" #include <wininet.h> const CString TIMECOMPARE = _T("%Y%m%d%H%M%S"); const CString TIMECOMPARE_DEFAULT = _T("19700101000000"); //********************************************************************* // MESSAGE MAP //********************************************************************* BEGIN_MESSAGE_MAP(CNetworkFileObject, CWinThread) ON_THREAD_MESSAGE(WMU_DOWNLOAD_START, OnStartDownload) END_MESSAGE_MAP() //********************************************************************* // CONSTRUCTOR & DESTRUCTOR //********************************************************************* IMPLEMENT_DYNCREATE(CNetworkFileObject, CWinThread) //===================================================================== CNetworkFileObject::CNetworkFileObject() { } //===================================================================== CNetworkFileObject::~CNetworkFileObject() { } //********************************************************************* // PUBLIC FUNCTIONS //********************************************************************* BOOL CNetworkFileObject::InitInstance() { // Initialize singleton classes m_pLog = CLog::Instance(); // Set our filepointer to NULL m_pNetworkFile = NULL; return TRUE; } //===================================================================== int CNetworkFileObject::ExitInstance() { // Always close file Close(); // Call original function return CWinThread::ExitInstance(); } //===================================================================== void CNetworkFileObject::SetParent(CWinThread * pParentThread) { // Set parent m_pParent = pParentThread; } //===================================================================== void CNetworkFileObject::SetTimeOut(int iTimeOut) { // Set value m_iTimeOut = iTimeOut; } //===================================================================== bool CNetworkFileObject::Open(CString sURL) { // If we are opened, close yourself first if (m_pNetworkFile) { Close(); } // Save information m_sURL = sURL; // Establish the connection return EstablishConnection(); } //===================================================================== int CNetworkFileObject::GetSize() { // Declare variables int iSize = -1; // Check if the file is open if (!m_pNetworkFile) { // We can't get size return iSize; } // Try to get filesize try { // Seek to end iSize = static_cast<int>(m_pNetworkFile->SeekToEnd()); } catch (CException * pEx) { #if defined _DEBUG || defined _BETA pEx->ReportError(); #endif // Delete exception object to prevent leaks pEx->Delete(); } // Return size return iSize; } //===================================================================== CString CNetworkFileObject::GetVersion() { // Declare variables CString sVersion = _T("0.0.0.0"); // Check if the file is open if (!m_pNetworkFile) { // We can't get version return sVersion; } // Not possible for internet files (yet) return sVersion; } //===================================================================== CString CNetworkFileObject::GetDate() { // Declare variables CString sDate = _T("1970-01-01"); CFileStatus fileStatus; // Check if the file is open if (!m_pNetworkFile) { // We can't get date return sDate; } // Try to get date try { // Get file status m_pNetworkFile->GetStatus(fileStatus); // Get date sDate.Format(_T("%04d-%02d-%02d"), fileStatus.m_mtime.GetYear(), fileStatus.m_mtime.GetMonth(), fileStatus.m_mtime.GetDay()); } catch (CException * pEx) { #if defined _DEBUG || defined _BETA pEx->ReportError(); #endif // Delete exception object to prevent leaks pEx->Delete(); } // Return date return sDate; } //===================================================================== CString CNetworkFileObject::GetDateTime() { // Declare variables CString sDateTime = _T("1970-01-01/00:00:00"); CFileStatus fileStatus; // Check if the file is open if (!m_pNetworkFile) { // We can't get date return sDateTime; } // Try to get date try { // Get file status m_pNetworkFile->GetStatus(fileStatus); // Get date sDateTime.Format(_T("%04d-%02d-%02d/%02d:%02d:%02d"), fileStatus.m_mtime.GetYear(), fileStatus.m_mtime.GetMonth(), fileStatus.m_mtime.GetDay(), fileStatus.m_mtime.GetHour(), fileStatus.m_mtime.GetMinute(), fileStatus.m_mtime.GetSecond()); } catch (CException * pEx) { #if defined _DEBUG || defined _BETA pEx->ReportError(); #endif // Delete exception object to prevent leaks pEx->Delete(); } // Return date return sDateTime; } //===================================================================== void CNetworkFileObject::Download(CString sDestination, bool bResumeIfPossible, HANDLE hEventStopDownloading) { // Check if the file is open if (!m_pNetworkFile) { // Send error report PostMessageToParent(WMU_ERROR, ERROR_FILENOTFOUND, 0); // Exit function return; } // Set options m_bResumeIfPossible = bResumeIfPossible; m_hEventStopDownloading = hEventStopDownloading; // Be sure the directory exists if (!PathFileExists(m_pPath->ExtractFilePath(sDestination))) { // It does not exist, create it CFunctions::Instance()->CreateFolder(m_pPath->ExtractFilePath(sDestination)); } // Check if file already exists if (PathFileExists(sDestination)) { // Set file attributes to normal so we are sure we are not dealing with a read-only file SetFileAttributes(sDestination, FILE_ATTRIBUTE_NORMAL); } try { // Set start reading byte to zero m_lStartReadingByte = 0; // Check if resume should be supported if (bResumeIfPossible) { // Check if resume is possible if (IsResumePossible(sDestination)) { // Yes, create file with append options m_pDestinationFile = new CFile(sDestination, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite | CFile::typeBinary); // Set start reading byte to size of new file m_lStartReadingByte = (int)m_pDestinationFile->SeekToEnd(); } else { // Create the resume file CreateResumeFile(sDestination); // Create file m_pDestinationFile = new CFile(sDestination, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary); } } else { // Create file m_pDestinationFile = new CFile(sDestination, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary); } } catch (CFileException * pEx) { #if defined _DEBUG || defined _BETA pEx->ReportError(); #endif // Delete exception object pEx->Delete(); // Send error report PostMessageToParent(WMU_ERROR, ERROR_DOWNLOADFILE, 0); // Exit return; } // Send yourself message to start PostThreadMessage(WMU_DOWNLOAD_START, 0, 0); } //===================================================================== void CNetworkFileObject::Close() { // Close file if (m_pNetworkFile) { m_pNetworkFile->Close(); delete m_pNetworkFile; } // Always set file pointer to NULL m_pNetworkFile = NULL; } //********************************************************************* // PRIVATE FUNCTIONS //********************************************************************* bool CNetworkFileObject::EstablishConnection() { // Check if file exists if (!PathFileExists(m_sURL)) { // Exit return false; } // Get original file try { m_pNetworkFile = new CFile(m_sURL, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone); } catch (CFileException * pEx) { #if defined _DEBUG || defined _BETA pEx->ReportError(); #endif // Delete exception object pEx->Delete(); // Send error report PostMessageToParent(WMU_ERROR, ERROR_COPYFILE, 0); // Exit return false; } // If we get here, connection is valid return true; } //===================================================================== void CNetworkFileObject::DownloadFile() { // Declare variables char szBuffer[BUFFER_DOWNLOADFILE]; int iFileBytes, iFileBytesCopied, iBytesRead; int iPreviousFileProgress = -1, iPreviousTotalProgress = -1; CFileStatus fileStatusLocation, fileStatusDestination; CString sNewFilePath; // Can we start? if (m_pDestinationFile == NULL) { // Send error message PostMessageToParent(WMU_ERROR, ERROR_DOWNLOADFILE, 0); // Exit this thread PostThreadMessage(WM_QUIT, 0, 0); } // Use try to catch errors try { // Get file date/time of original file m_pNetworkFile->GetStatus(fileStatusLocation); // Seek to end iFileBytes = static_cast<int>(m_pNetworkFile->SeekToEnd()); // Check if we can skip file if (iFileBytes != m_lStartReadingByte) { // Move cursor back to start byte m_pNetworkFile->Seek(m_lStartReadingByte, CFile::begin); // Set bytes copied (is needed if resume is enabled) iFileBytesCopied = m_lStartReadingByte; // Move cursor of write file to end of file m_pDestinationFile->SeekToEnd(); // Read from file while (iBytesRead = m_pNetworkFile->Read(szBuffer, BUFFER_DOWNLOADFILE)) { // Write actual data into file m_pDestinationFile->Write(szBuffer, iBytesRead); // Update copied bytes iFileBytesCopied += iBytesRead; // Send copy status to parent SendDownloadStatus(iFileBytesCopied, iFileBytes); // Check if we are allowed to read again if (WaitForSingleObject(m_hEventStopDownloading, 0) == WAIT_OBJECT_0) { // No, stop download return; } } } // Get new file path sNewFilePath = m_pDestinationFile->GetFilePath(); // Set file date/time of original file m_pDestinationFile->GetStatus(fileStatusDestination); m_pDestinationFile->Close(); } // If there where any errors, catch them catch (CException * pEx) { #if defined _DEBUG || defined _BETA pEx->ReportError(); #endif // Delete exception object to prevent leaks pEx->Delete(); // Post error PostMessageToParent(WMU_ERROR, ERROR_DOWNLOADFILE, 0); } // Try to set filestatus try { fileStatusDestination.m_atime = fileStatusLocation.m_atime; fileStatusDestination.m_ctime = fileStatusLocation.m_ctime; fileStatusDestination.m_mtime = fileStatusLocation.m_mtime; CFile::SetStatus(sNewFilePath, fileStatusDestination); } catch (CException * pEx) { // Not important pEx->Delete(); } } //===================================================================== bool CNetworkFileObject::IsResumePossible(CString sDestination) { // Declare variables CString sResumeFile, sResumeInfo, sTemp = _T(""); CFile * pResumeFile; CFileStatus fsOriginalFile; int iFileSize; // Set up resume file path sResumeFile = sDestination + _T(".rsm"); // Check if we can find any part of the file on harddisk if (!PathFileExists(sDestination)) return false; // Check if we can find resume file if (!PathFileExists(sResumeFile)) return false; try { // Open resume file pResumeFile = new CFile(sResumeFile, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone); // Get file size iFileSize = (int)pResumeFile->SeekToEnd(); pResumeFile->SeekToBegin(); // Read value from resume file pResumeFile->Read(sTemp.GetBuffer(iFileSize), iFileSize); sResumeInfo = sTemp.GetBuffer(iFileSize); //sTemp.ReleaseBuffer(); // Close resume file pResumeFile->Close(); // Delete memory for file delete pResumeFile; } catch (CException * pEx) { pEx->Delete(); return false; } // Get file status of original file m_pNetworkFile->GetStatus(fsOriginalFile); // First check if we are dealing with a default date if (sResumeInfo == TIMECOMPARE_DEFAULT) return false; // Compare current time with saved time if (fsOriginalFile.m_mtime.Format(TIMECOMPARE) != sResumeInfo) return false; // If we get here, resume is possible return true; } //===================================================================== void CNetworkFileObject::CreateResumeFile(CString sDestination) { // Declare variables CString sResumeFile; CFile * pResumeFile; CFileStatus fsOriginalFile; // Set up resume file path sResumeFile = sDestination + _T(".rsm"); // Get file status of original file m_pNetworkFile->GetStatus(fsOriginalFile); try { // Open resume file pResumeFile = new CFile(sResumeFile, CFile::modeCreate | CFile::modeWrite); // Write value to resume file pResumeFile->Write(fsOriginalFile.m_mtime.Format(TIMECOMPARE), fsOriginalFile.m_mtime.Format(TIMECOMPARE).GetLength()); // Close resume file pResumeFile->Close(); // Delete memory for file delete pResumeFile; } catch (CException * pEx) { pEx->Delete(); } } //===================================================================== void CNetworkFileObject::SendDownloadStatus(int iBytesCopied, int iTotalBytes) { // Declare variables int iPercentageCompleted, iCurrentActionPoints, iTemp; // Calculate current percentage completed if (iBytesCopied > INT_MAX / 100) { // Size is getting too large, go a few steps back iTemp = iBytesCopied / 10000; // Calculate it iPercentageCompleted = iTemp / (iTotalBytes / 1000000); } else { // Calculate percentage on a normal way iPercentageCompleted = (iBytesCopied * 100) / iTotalBytes; } // Because sometimes we are not very accurate if (iPercentageCompleted > 100) { iPercentageCompleted = 100; } // Calculate current actionpoints completed iCurrentActionPoints = (iPercentageCompleted * m_iActionPoints) / 100; // Send information to parent if (m_pParent && (m_iCurrentActionPoints != iCurrentActionPoints)) { m_iCurrentActionPoints = iCurrentActionPoints; // Send status PostMessageToParent(WMU_DOWNLOAD_STATUS, m_iCurrentActionPoints, m_iActionPoints); } } //===================================================================== void CNetworkFileObject::PostMessageToParent(UINT message, WPARAM wParam, LPARAM lParam) { // Check if parent is still valid if (!IsBadReadPtr(m_pParent, sizeof(CWinThread *))) { // Send message m_pParent->PostThreadMessage(message, wParam, lParam); } } //===================================================================== CString CNetworkFileObject::ExtractFilePath(CString sFilename) { // Declare variables int iPos; // Now search for the last backslash for (int i = sFilename.GetLength(); i > 0; i--) { iPos = sFilename.Find(_T('\\'), sFilename.GetLength()-(sFilename.GetLength()-i)); // If we found them, delete last piece if (iPos != -1) { sFilename.Delete(iPos, sFilename.GetLength()-i); return sFilename; } } // If we not found, we are already dealing with path return sFilename; } //===================================================================== bool CNetworkFileObject::CreateFolder(CString sFolder) { // Declare variables DWORD dwAttrib = GetFileAttributes(sFolder); CString sTemp; // Is folder already existing? if (PathFileExists(sFolder)) return true; // Recursively create from the top down int iPos = sFolder.ReverseFind(_T('\\')); if (iPos != -1) { // The parent is a dir, not a drive sTemp = sFolder; sTemp.Delete(iPos, sFolder.GetLength() - iPos); // if can't create parent if (!CreateFolder(sTemp)) { return false; } // Check if last character is a backslash if (sTemp.GetAt(sTemp.GetLength() - 1) == _T('\\')) return true; // Check if path exists if (PathFileExists(sFolder)) return true; // Try to create directory if (!::CreateDirectory(sFolder, NULL)) return false; } // If we get here, function is successful return true; } //===================================================================== void CNetworkFileObject::OnStartDownload(WPARAM wParam, LPARAM lParam) { // Init action points m_iCurrentActionPoints = 0; m_iActionPoints = CActionPoints::CalculateActionPoints(static_cast<int>(m_pNetworkFile->GetLength())); // Start the copy process DownloadFile(); // Send message to parent that we are ready PostMessageToParent(WMU_DOWNLOAD_COMPLETE, 0, 0); }